package com.svse.services.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.svse.dao.UserredpacketMapper;
import com.svse.entity.UserredpacketEntity;
import com.svse.services.RedisRedPacketService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;

/**
 * @author LiYuhang
 * @version 0.1
 * @application
 * @Copyright 上海危网信息科技有限公司版权所有
 * @company wwsoft
 * @Date 2019/11/25 15:17
 */
@Service
@Slf4j
public class RedisRedPacketServiceImpl  extends ServiceImpl<UserredpacketMapper, UserredpacketEntity> implements RedisRedPacketService {
    private static final String PREFIX="red_packet_list_";
    /**
     *每次取出100条，避免一次取出消耗太多内存
     */
    private static final int TIME_SIZE=100;
    @Autowired
    private RedisTemplate redisTemplate;


    String script = "local listKey = 'red_packet_list_'..KEYS[1] \n"// 被抢红包列表 key
            + "local redPacket = 'red_packet_'..KEYS[1] \n"       // 当前被抢红包 key
            + "local stock = tonumber(redis.call('hget', redPacket, 'stock')) \n"// 读取当前红包库存
            + "if stock <= 0 then return 0 end \n"                // 没有库存，返回0
            + "stock = stock -1 \n"                               // 库存减1
            + "redis.call('hset', redPacket, 'stock', tostring(stock)) \n"// 保存当前库存
            + "redis.call('rpush', listKey, ARGV[1]) \n"          // 往Redis链表中加入当前红包信息
            + "if stock == 0 then return 2 end \n"                // 如果是最后一个红包，则返回2，表示抢红包已经结束，需要将Redis列表中的数据保存到数据库中
            + "return 1 \n";

    // 在缓存LUA脚本后，使用该变量保存Redis返回的32位的SHA1编码，使用它去执行缓存的LUA脚本[加入这句话]
    String sha1=null;

    @Override
    @Async  // 开启新线程运行（意思是让spring自动创建另外一条线程去运行它）
    public void saveUserRedPacketByRedis(int redPacketId, Double unitAmount) {
        log.error("开始保存数据");
        Long start = System.currentTimeMillis();
        // 获取列表操作对象
        BoundListOperations ops = redisTemplate.boundListOps(PREFIX + redPacketId);
        Long size = ops.size();
        Long times = size % TIME_SIZE == 0 ? size / TIME_SIZE : size / TIME_SIZE + 1;
        int count = 0;
        List<UserredpacketEntity> userRedPacketList = new ArrayList<UserredpacketEntity>(TIME_SIZE);
        for (int i = 0; i < times; i++) {
            // 获取至多TIME_SIZE个抢红包信息
            List userIdList = null;
            if (i == 0) {
                userIdList = ops.range(i * TIME_SIZE, (i + 1) * TIME_SIZE);
            } else {
                userIdList = ops.range(i * TIME_SIZE + 1, (i + 1) * TIME_SIZE);
            }
            userRedPacketList.clear();
            // 保存红包信息
            for (int j = 0; j < userIdList.size(); j++) {
                String args = userIdList.get(j).toString();
                String[] arr = args.split("-");
                String userIdStr = arr[0];
                String timeStr = arr[1];
                int userId =Integer.parseInt(userIdStr);
                Long time = Long.parseLong(timeStr);
                // 生成抢红包信息
                UserredpacketEntity userRedPacket = new UserredpacketEntity();
                userRedPacket.setRedPacketId(redPacketId);
                userRedPacket.setUserId(userId);
                userRedPacket.setAmount(unitAmount);
                userRedPacket.setGlobalDate(new Timestamp(time));
                userRedPacket.setNote("抢红包 " + redPacketId);
                userRedPacketList.add(userRedPacket);
            }
            // 插入抢红包信息
            this.saveBatch(userRedPacketList);
            count+=userRedPacketList.size();
        }
        // 删除Redis列表
        redisTemplate.delete(PREFIX + redPacketId);//目的是释放内存资源
        Long end = System.currentTimeMillis();
        log.error("保存数据结束，耗时" + (end - start) + "毫秒，共" + count + "条记录被保存。");

    }
}
